﻿Imports WSEntidades
Imports Utilerias
Imports WSDatos

Public Class CertificadosBL
    Public Function RegistrarCertificado(ByVal TokenConexion As String, ByVal rfcEmpresa As String, ByVal certificado As CertificadoBE,
                                         ByRef detResp As DetalleRespuesta) As Boolean
        Dim certDAL As CertificadoDAL = New CertificadoDAL("")
        detResp.Mensajes = ""
        Try
            TokenConexion = RijndaelSimple.desencriptaDefault(TokenConexion)
            If (EsValidoParaRegistrar(rfcEmpresa, certificado, detResp.Mensajes)) Then
                certDAL = New CertificadoDAL(TokenConexion)
                If (certDAL.existeCertificado(certificado.NumeroCertificado)) Then
                    detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.Catalogo_PreviamenteRegistrado,
                                                 String.Format("Existe un registro previo con el Número de Certificado <{0}>.{1}", certificado.NumeroCertificado, vbCrLf) &
                                                  detResp.Mensajes)
                    Return False
                Else
                    If (certDAL.registrarCertificado(certificado)) Then
                        detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ProcesamientoOK,
                                                 "El certificado se registró con éxito.")
                        Return True
                    Else
                        detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.Catalogo_NoFueRegistrado,
                                                 "El certificado no pudo ser registrado en el sistema.")
                        Return False
                    End If
                End If
            Else
                detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ValoresInvalidos,
                                         "El Certificado no es valido para registrar: " & vbCrLf & detResp.Mensajes)
                Return False
            End If
        Catch ex As Exception
            Log.LogException(ex, "CertificadosBL.RegistrarCertificado")
            detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ExcepcionEnOperacion,
                                     detResp.Mensajes & "Excepción al registrar el certificado: " & ex.Message)
            Return False
        Finally
            certDAL = Nothing
        End Try
    End Function

    Private Function EsValidoParaRegistrar(ByRef rfcEmpresa As String, ByRef certificado As CertificadoBE, ByRef mensajes As String) As Boolean
        Dim rfcSujeto As String = ""
        Dim rutaCert As String = ""
        Dim rutaKey As String = ""
        Dim rutaOpenssl As String = ""
        Try
            If (String.IsNullOrWhiteSpace(rfcEmpresa)) Then
                mensajes &= "El RFC de la Empresa es requerido, no puede ir el campo vacío." & vbCrLf
            Else
                rfcEmpresa = rfcEmpresa.Trim.ToUpper
                Select Case rfcEmpresa.Length
                    Case 12
                        If (Not csValidaciones.esRFCValidoPersonaMoral(rfcEmpresa)) Then
                            mensajes &= String.Format("El RFC <{0}> no es válido para Persona Moral.{1}", rfcEmpresa, vbCrLf)
                        End If
                    Case 13
                        If (Not csValidaciones.esRFCValidoPersonaFisica(rfcEmpresa)) Then
                            mensajes &= String.Format("El RFC <{0}> no es válido para Persona Física.{1}", rfcEmpresa, vbCrLf)
                        End If
                    Case Else
                        mensajes &= String.Format("Longitud no válida para RFC <{0}>.{1}", rfcEmpresa, vbCrLf)
                End Select
            End If

            If (certificado.CertificadoPublico Is Nothing) Then
                mensajes &= "El Certificado Público es obligatorio, no puede ir el campo vacío." & vbCrLf
            Else
                If (certificado.CertificadoPublico.Length <= 0) Then
                    mensajes &= "El Certificado Público no contiene datos." & vbCrLf
                End If
            End If

            If (certificado.CertificadoPrivado Is Nothing) Then
                mensajes &= "La Llave Privada es obligatoria, no puede ir el campo vacío." & vbCrLf
            Else
                If (certificado.CertificadoPrivado.Length <= 0) Then
                    mensajes &= "La Llave Privada no contiene datos." & vbCrLf
                End If
            End If

            If String.IsNullOrWhiteSpace(certificado.ContraseñaPrivada) Then
                mensajes &= "La Contraseña de la Llave Privada del Certificado es obligatoria, no puede ir el campo vacío." & vbCrLf
            End If

            If (mensajes = "") Then
                certificado.NumeroCertificado = ""
                certificado.InicioVig = Nothing
                certificado.FinVig = Nothing
                'Se tienen los archivos y la contraseña, empezar a obtener información de los certificados y a validarlos
                certificado.NumeroCertificado = csCertificadosSAT.getSerieCertificado(Convert.FromBase64String(certificado.CertificadoPublico), _
                                                                                      certificado.InicioVig, certificado.FinVig, rfcSujeto)

                If ((certificado.NumeroCertificado.Trim.Length = 20) And
                    (rfcSujeto.Trim.Length = 12 Or rfcSujeto.Trim.Length = 13) And
                    (certificado.InicioVig <> Nothing) And
                    (certificado.FinVig <> Nothing)) Then
                    If (rfcEmpresa.Equals(rfcSujeto.ToUpper.Trim)) Then
                        rutaCert = csArchivos.escribeArchivoDesdeBytearray(My.Settings.PathFiles, certificado.NumeroCertificado & ".cer", _
                                                                           Convert.FromBase64String(certificado.CertificadoPublico))
                        rutaKey = csArchivos.escribeArchivoDesdeBytearray(My.Settings.PathFiles, certificado.NumeroCertificado & ".key", _
                                                                          Convert.FromBase64String(certificado.CertificadoPrivado))
                        rutaOpenssl = My.Settings.PathFiles & "Openssl\openssl.exe"
                        If (System.IO.File.Exists(rutaCert) AndAlso System.IO.File.Exists(rutaKey) AndAlso System.IO.File.Exists(rutaOpenssl)) Then
                            csCertificadosSAT.validaCertificados(rutaOpenssl, rutaCert, rutaKey, DateTime.Now, certificado.ContraseñaPrivada, rfcSujeto,
                                                                     certificado.NumeroCertificado, certificado.InicioVig, certificado.FinVig, mensajes)
                            If (mensajes = "") Then
                                certificado.Pfx = csCertificadosSAT.convierteAPfx(rutaOpenssl, rutaCert, rutaKey, certificado.ContraseñaPrivada, mensajes)
                                If (certificado.Pfx Is Nothing) Then
                                    Log.writeLog("Error al generar PFX  de certificado: " & certificado.NumeroCertificado & ": " & mensajes)
                                    mensajes = Nothing
                                End If
                            End If
                            System.IO.File.Delete(rutaCert)
                            System.IO.File.Delete(rutaKey)
                        Else
                            mensajes &= "No se grabaron los Certificados proporcionados o no existen herramientas necesarias." & vbCrLf
                        End If
                    Else
                        mensajes &= String.Format("Los Certificados proporcionados NO pertenecen al RFC <{0}>. (<{1}>). {2}", rfcEmpresa, rfcSujeto, vbCrLf)
                    End If
                Else
                    mensajes &= "No se logró obtener la información básica para validar los Certificados, verifique sean correctos." & vbCrLf
                End If
            End If

            Return (mensajes = "")

        Catch ex As Exception
            Log.LogException(ex, "CertificadosBL.EsValidoParaRegistrar")
            mensajes &= ex.Message
            Return False
        Finally
            rfcSujeto = Nothing
            rutaCert = Nothing
            rutaKey = Nothing
            rutaOpenssl = Nothing
        End Try
    End Function

    Public Function CambiarEstadoCertificado(ByVal tokenConexion As String, ByVal numCertif As String, ByVal nuevoEstado As CertificadoBE.estadoCertificado,
                                             ByRef detResp As DetalleRespuesta) As Boolean
        detResp.Mensajes = ""
        Dim certDAL As CertificadoDAL = New CertificadoDAL("")
        Try
            certDAL = New CertificadoDAL(RijndaelSimple.desencriptaDefault(tokenConexion))
            If (EsValidoParaActualizar(numCertif, detResp.Mensajes)) Then
                If (certDAL.actualizarEstadoCertificado(numCertif, nuevoEstado)) Then
                    detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ProcesamientoOK,
                                             "El Certificado ha cambiado su estado")
                    Return True
                Else
                    detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.Catalogo_NoFueActualizado,
                                             String.Format("No se pudo realizar la actualización de estado del Certificado <{0}> o el Certificado <{0}> no existe", numCertif))
                    Return False
                End If
            Else
                detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ValoresInvalidos,
                                         "La información no es válida para actualizar: " & vbCrLf & detResp.Mensajes)
                Return False
            End If
        Catch ex As Exception
            Log.LogException(ex, "CertificadosBL.CambiarEstadoCertificado")
            detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ExcepcionEnOperacion,
                                     detResp.Mensajes & String.Format("Excepción al actualizar estado del Certificado <{0}>: {1}", numCertif, ex.Message))
            Return False
        Finally
            certDAL = Nothing
        End Try
    End Function

    Private Function EsValidoParaActualizar(ByRef numCertif As String, ByRef msg As String) As Boolean
        msg = ""
        Try
            If (String.IsNullOrWhiteSpace(numCertif)) Then
                msg &= "El Número de Certificado es requerido." & vbCrLf
            Else
                numCertif = numCertif.Trim()
                If (Not csValidaciones.esNumeroDeCertificadoValido(numCertif)) Then
                    msg &= String.Format("El Número de Certificado <{0}> no es válido, debe constar de 20 dígitos.{1}", numCertif, vbCrLf)
                End If
            End If

            Return (msg = "")
        Catch ex As Exception
            Log.LogException(ex, "CertificadosBL.EsValidoParaActualizar")
            msg &= ex.Message
            Return False
        End Try
    End Function

    Function EstablecerCertificadoDeCancelacion(ByVal tokenConexion As String, ByVal numCertif As String, ByRef detResp As DetalleRespuesta) As Boolean
        detResp.Mensajes = ""
        Dim certDAL As CertificadoDAL = New CertificadoDAL("")
        Try
            certDAL = New CertificadoDAL(RijndaelSimple.desencriptaDefault(tokenConexion))
            If (EsValidoParaActualizar(numCertif, detResp.Mensajes)) Then
                If (certDAL.establecerUsoDeCancelacion(numCertif)) Then
                    detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ProcesamientoOK,
                                             "El Certificado se ha configurado para cancelación")
                    Return True
                Else
                    detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.Catalogo_NoFueActualizado,
                                             String.Format("No se pudo establecer el Certificado <{0}> como de cancelación o el Certificado <{0}> no existe", numCertif))
                    Return False
                End If
            Else
                detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ValoresInvalidos,
                                     "La información no es válida para actualizar: " & vbCrLf & detResp.Mensajes)
                Return False
            End If
        Catch ex As Exception
            Log.LogException(ex, "CertificadosBL.EstablecerCertificadoDeCancelacion")
            detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ExcepcionEnOperacion,
                                     detResp.Mensajes & String.Format("Excepción al establecer Certificado de cancelación<{0}>: {1}", numCertif, ex.Message))
            Return False
        Finally
            certDAL = Nothing
        End Try
    End Function

    Function GetCertificado(ByVal tokenConexion As String, ByVal numCertif As String, ByRef detResp As DetalleRespuesta) As CertificadoBE
        detResp.Mensajes = ""
        Dim certDAL As CertificadoDAL = New CertificadoDAL("")
        Dim certBE As CertificadoBE = New CertificadoBE
        Try
            certDAL = New CertificadoDAL(RijndaelSimple.desencriptaDefault(tokenConexion))
            If (EsValidoParaActualizar(numCertif, detResp.Mensajes)) Then
                certBE = certDAL.getCertificado(numCertif)
                If (certBE IsNot Nothing) Then
                    detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ProcesamientoOK,
                                             "Se obtuvo la información del certificado con éxito")
                    Return certBE
                Else
                    detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.Catalogo_RegistroInexistenteOInactivo,
                                             String.Format("No se obtuvo información del Certificado <{0}> o el Certificado <{0}> no existe", numCertif))
                    Return Nothing
                End If
            Else
                detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ValoresInvalidos,
                                     "La información no es válida para obtener datos del Certificado: " & vbCrLf & detResp.Mensajes)
                Return Nothing
            End If
        Catch ex As Exception
            Log.LogException(ex, "CertificadosBL.GetCertificado")
            detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ExcepcionEnOperacion,
                                     detResp.Mensajes & String.Format("Excepción al obtener información del Certificado <{0}>: {1}", numCertif, ex.Message))
            Return Nothing
        Finally
            certDAL = Nothing
            certBE = Nothing
        End Try
    End Function

    Function GetCertificadoDeCancelacion(ByVal tokenConexion As String, ByRef detResp As DetalleRespuesta) As CertificadoBE
        detResp.Mensajes = ""
        Dim certDAL As CertificadoDAL = New CertificadoDAL("")
        Dim certBE As CertificadoBE = New CertificadoBE
        Try
            certDAL = New CertificadoDAL(RijndaelSimple.desencriptaDefault(tokenConexion))
            certBE = certDAL.getCertificadoDeCancelacion()
            If (certBE IsNot Nothing) Then
                detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ProcesamientoOK,
                                         "Se obtuvo la información del certificado de cancelación con éxito")
                Return certBE
            Else
                detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.Catalogo_RegistroInexistenteOInactivo,
                                         "No se obtuvo información del Certificado de Cancelación o no se ha establecido el uso")
                Return Nothing
            End If
            
        Catch ex As Exception
            Log.LogException(ex, "CertificadosBL.GetCertificadoDeCancelacion")
            detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ExcepcionEnOperacion,
                                     detResp.Mensajes & String.Format("Excepción al obtener información del Certificado de Cancelación: {0}", ex.Message))
            Return Nothing
        Finally
            certDAL = Nothing
            certBE = Nothing
        End Try
    End Function

    Function GetListadoCertificados(ByVal tokenConexion As String, ByVal tipo As Enumeraciones.tiposCertificadosParaBusquedas,
                                    ByVal estatus As Enumeraciones.estatusParaBusquedas, ByRef detResp As DetalleRespuesta) As List(Of CertificadoBE)
        detResp.Mensajes = ""
        Dim certDAL As CertificadoDAL = New CertificadoDAL("")
        Dim lsCertBE As List(Of CertificadoBE)
        Try
            certDAL = New CertificadoDAL(RijndaelSimple.desencriptaDefault(tokenConexion))
            lsCertBE = certDAL.GetListadoCertificados(tipo, estatus)
            If (lsCertBE IsNot Nothing) Then
                detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ProcesamientoOK,
                                         "Se obtuvo listado de Certificados con éxito")
                Return lsCertBE
            Else
                detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.Catalogo_NoObtuvoRegistrosParaListado,
                                         "No se obtuvo el listado de Certificados")
                Return Nothing
            End If
        Catch ex As Exception
            Log.LogException(ex, "CertificadosBL.GetListadoCertificados")
            detResp.estableceValores(DetalleRespuesta.CodigoRespuesta.ExcepcionEnOperacion,
                                     detResp.Mensajes & "Excepción al obtener el listado de Certificados: " & ex.Message)
            Return Nothing
        Finally
            certDAL = Nothing
            lsCertBE = Nothing
        End Try
    End Function

End Class
